﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Messaging;
using Common;
using GameServer;
using MQueue.SubsWebService;

namespace MQueue
{
	public partial class MQueue : ServiceBase
	{
		private Server _gameSrv = null;
        private string _mqname;
		private MessageQueue _mqGame;
        private UserListSender userListSender;
		private EventLog _eventLog;
		private SubsWebService.SubService _subsService;

		public MQueue()
		{
			InitializeComponent();
			_eventLog = new EventLog("Battleships Log", ".", "Battleships");
		}

		protected override void OnStart(string[] args)
		{
            //create the web service interface
			_subsService = new SubService();

            userListSender = new UserListSender(SendUserListAsync);
            _mqname = Properties.Settings.Default.QueueName;
			Server.QueueName = _mqname;
			Server.BufferSize = Properties.Settings.Default.BufferSize;
			Server.AliveInterval = Properties.Settings.Default.TimerInterval;
			_gameSrv = Server.GetServerSingleton(Properties.Settings.Default.ServerPort);

            if (MessageQueue.Exists(_mqname))
                _mqGame = new MessageQueue(_mqname);
            else
            {
                _mqGame = MessageQueue.Create(_mqname);
                try
                {
                    _mqGame.SetPermissions("BUILTIN\\Administrators", MessageQueueAccessRights.FullControl);
                    _mqGame.SetPermissions("BUILTIN\\SYSTEM", MessageQueueAccessRights.FullControl);
                }
                catch { }
            }
			_eventLog.WriteEntry("Service started", EventLogEntryType.Information);

			_mqGame.Formatter = new XmlMessageFormatter(new Type[] { typeof(ServerCommand), typeof(ClientCommand), typeof(ServerCommandType), typeof(ClientCommandType) });
			_mqGame.ReceiveCompleted += new ReceiveCompletedEventHandler(_mqGame_ReceiveCompleted);
			_mqGame.BeginReceive();
		}

		private void _mqGame_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
		{
            _eventLog.WriteEntry("Message received", EventLogEntryType.Information);
			try
			{
				Message msg = ((MessageQueue)sender).EndReceive(e.AsyncResult);
				ICommand cmd = msg.Body as ICommand;
				if (cmd is ClientCommand)
					ProcessClientCommand(cmd as ClientCommand);
				else
				{
					throw new Exception("Error!");
				}
			}
			catch (Exception ex)
			{
				_eventLog.WriteEntry("Error: " + ex.Message, EventLogEntryType.Error);
			}
			finally
			{
				_mqGame.BeginReceive();
			}
		}

		protected override void OnStop()
		{
			_gameSrv.Dispose();
			_eventLog.WriteEntry("Service stopped", EventLogEntryType.Information);
		}

		private void ProcessClientCommand(ClientCommand clientCmd)
		{
            _eventLog.WriteEntry("Command received: " + clientCmd.ComTypeClient.ToString(), EventLogEntryType.Information);
			string opponent = "";
			if (clientCmd.User != "")
				_gameSrv.findClientByName(clientCmd.User).AliveResponse = 0;
			switch (clientCmd.ComTypeServer)
			{
				case ServerCommandType.Null: // The command was initiated by client
					_gameSrv.sendCommand(clientCmd.User, new ServerCommand(clientCmd.ComTypeClient, clientCmd.User, true));
					switch (clientCmd.ComTypeClient)
					{
						case ClientCommandType.Logout:
                            _gameSrv.RemoveConnection(clientCmd.User);
                            _subsService.GameOverAsync(clientCmd.User, true);// Call GameOver method from webservice
                            _subsService.LogOutAsync(clientCmd.User);// Call Logout method from webservice
							break;
						case ClientCommandType.GameOpen:
                            _subsService.CreateGame(clientCmd.User);// Call OpenGame method from webservice
							break;
						case ClientCommandType.GameRequest:
							_gameSrv.sendCommand(clientCmd.Message, new ServerCommand(ServerCommandType.GameRequested, clientCmd.Message, clientCmd.User));
							break;
						case ClientCommandType.GameAccept:
                            try
                            {
                            _gameSrv.findClientByName(clientCmd.User).Opponent = clientCmd.Message;
                            _gameSrv.findClientByName(clientCmd.Message).Opponent = clientCmd.User;
                            }
                            catch{}
                            _subsService.CommitGameAsync(clientCmd.User, clientCmd.Message);// Call CommitGame method on webservice
							_gameSrv.sendCommand(clientCmd.Message, new ServerCommand(ServerCommandType.GameAccepted, clientCmd.Message, ""));
							break;
						case ClientCommandType.GameReady:
                            _gameSrv.sendCommand(_gameSrv.findClientByName(clientCmd.User).Opponent, new ServerCommand(ServerCommandType.OpponentReady, opponent, ""));
							break;
						case ClientCommandType.GameMove:
                            _gameSrv.sendCommand(_gameSrv.findClientByName(clientCmd.User).Opponent, new ServerCommand(ServerCommandType.RedirectMove, opponent, clientCmd.Column, clientCmd.Row, ""));
							break;
						case ClientCommandType.GameMoveResuslt:
                            _gameSrv.sendCommand(_gameSrv.findClientByName(clientCmd.User).Opponent, new ServerCommand(ServerCommandType.MoveResult, opponent, clientCmd.Column, clientCmd.Row, clientCmd.Message));
							break;
						case ClientCommandType.GameNew:
                            _gameSrv.sendCommand(_gameSrv.findClientByName(clientCmd.User).Opponent, new ServerCommand(ServerCommandType.GameNew, opponent, clientCmd.User));
							break;
						case ClientCommandType.GameResign:
                            _gameSrv.sendCommand(_gameSrv.findClientByName(clientCmd.User).Opponent, new ServerCommand(ServerCommandType.Resign, opponent, ""));
							_subsService.GameOverAsync(clientCmd.User, true);
							break;
						case ClientCommandType.Message:
                            _gameSrv.sendCommand(_gameSrv.findClientByName(clientCmd.User).Opponent, new ServerCommand(ServerCommandType.Message, opponent, clientCmd.Message));
							break;
						case ClientCommandType.Alive:
						case ClientCommandType.OpenGames:
							_eventLog = new EventLog("Battleships Log", ".", "Battleships");
							_eventLog.WriteEntry("Get Open Games List", EventLogEntryType.Information);
                            _gameSrv.sendCommand(clientCmd.User, new ServerCommand(ServerCommandType.OpenGames, clientCmd.User, "A" + Environment.NewLine + "B" + Environment.NewLine + "C"));
                            userListSender.BeginInvoke(clientCmd, null, null);
							break;
					}
					break;
				case ServerCommandType.GameAccepted: // Accept command was received by client
					break;
				case ServerCommandType.MoveResult: // Move result was received successfully
					break;
				case ServerCommandType.RedirectMove: // Move redirection succeed
					break;
				case ServerCommandType.IsAlive: // The client is alive
					break;
				case ServerCommandType.OnlineList: // Online list received by client
					break;
				case ServerCommandType.OpenGames: // Games list received by client
					break;
				case ServerCommandType.Message: // Message received
					break;
			}
		}

        public delegate void UserListSender(ClientCommand clientCmd);

        public void SendUserListAsync(ClientCommand clientCmd)
        {
            string[] openGames = _subsService.GetOpennedGames();
			string userList = (openGames.Length > 0) ? string.Join(Environment.NewLine, openGames) : "";
            _gameSrv.sendCommand(clientCmd.User, new ServerCommand(ServerCommandType.OpenGames, clientCmd.User, userList));// Get list of open games from webservice
        }
	}
}
